home *** CD-ROM | disk | FTP | other *** search
/ Collection of Internet / Collection of Internet.iso / msdos / lynx / source / www / library / implemen / htaabrow.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-25  |  27.6 KB  |  953 lines

  1.  
  2. /* MODULE                            HTAABrow.c
  3. **        BROWSER SIDE ACCESS AUTHORIZATION MODULE
  4. **
  5. **    Containts the code for keeping track on server hostnames,
  6. **    port numbers, scheme names, usernames, passwords
  7. **    (and servers' public keys).
  8. **
  9. ** IMPORTANT:
  10. **    Routines in this module use dynamic allocation, but free
  11. **    automatically all the memory reserved by them.
  12. **
  13. **    Therefore the caller never has to (and never should)
  14. **    free() any object returned by these functions.
  15. **
  16. **    Therefore also all the strings returned by this package
  17. **    are only valid until the next call to the same function
  18. **    is made. This approach is selected, because of the nature
  19. **    of access authorization: no string returned by the package
  20. **    needs to be valid longer than until the next call.
  21. **
  22. **    This also makes it easy to plug the AA package in:
  23. **    you don't have to ponder whether to free() something
  24. **    here or is it done somewhere else (because it is always
  25. **    done somewhere else).
  26. **
  27. **    The strings that the package needs to store are copied
  28. **    so the original strings given as parameters to AA
  29. **    functions may be freed or modified with no side effects.
  30. **
  31. **    The AA package does not free() anything else than what
  32. **    it has itself allocated.
  33. **
  34. ** AUTHORS:
  35. **    AL    Ari Luotonen    luotonen@dxcern.cern.ch
  36. **
  37. ** HISTORY:
  38. **    Oct 17    AL    Made corrections suggested by marca:
  39. **            Added  if (!realm->username) return NULL;
  40. **            Changed some ""s to NULLs.
  41. **            Now doing calloc() to init uuencode source;
  42. **            otherwise HTUU_encode() reads uninitialized memory
  43. **            every now and then (not a real bug but not pretty).
  44. **            Corrected the formula for uuencode destination size.
  45. ** BUGS:
  46. **
  47. **
  48. */
  49.  
  50. #include"capalloc.h"
  51. #include"capstdio.h"
  52. #include <string.h>        /* strchr() */
  53.  
  54. #include "HTUtils.h"
  55. #include "HTString.h"
  56. #include "HTParse.h"        /* URL parsing function        */
  57. #include "HTList.h"        /* HTList object        */
  58. #include "HTAlert.h"        /* HTConfirm(), HTPrompt()    */
  59. #include "HTAAUtil.h"        /* AA common to both sides    */
  60. #include "HTAssoc.h"        /* Assoc list            */
  61. #include "HTAABrow.h"        /* Implemented here        */
  62. #include "HTUU.h"        /* Uuencoding and uudecoding    */
  63.  
  64.  
  65.  
  66. /*
  67. ** Local datatype definitions
  68. **
  69. ** HTAAServer contains all the information about one server.
  70. */
  71. typedef struct {
  72.  
  73.     char *    hostname;    /* Host's name            */
  74.     int        portnumber;    /* Port number            */
  75.     HTList *    setups;        /* List of protection setups    */
  76.                                 /* on this server; i.e. valid    */
  77.                                 /* authentication schemes and    */
  78.                                 /* templates when to use them.    */
  79.                                 /* This is actually a list of    */
  80.                                 /* HTAASetup objects.        */
  81.     HTList *    realms;        /* Information about passwords    */
  82. } HTAAServer;
  83.  
  84.  
  85. /*
  86. ** HTAASetup contains information about one server's one
  87. ** protected tree of documents.
  88. */
  89. typedef struct {
  90.     HTAAServer *server;        /* Which server serves this tree         */
  91.     char *    template;    /* Template for this tree             */
  92.     HTList *    valid_schemes;    /* Valid authentic.schemes                */
  93.     HTAssocList**scheme_specifics;/* Scheme specific params             */
  94.     BOOL    retry;        /* Failed last time -- reprompt (or whatever)*/
  95. } HTAASetup;
  96.  
  97.  
  98. /*
  99. ** Information about usernames and passwords in
  100. ** Basic and Pubkey authentication schemes;
  101. */
  102. typedef struct {
  103.     char *    realmname;    /* Password domain name        */
  104.     char *    username;    /* Username in that domain    */
  105.     char *    password;    /* Corresponding password    */
  106. } HTAARealm;
  107.  
  108.  
  109.  
  110. /*
  111. ** Module-wide global variables
  112. */
  113.  
  114. PRIVATE HTList *server_table    = NULL;    /* Browser's info about servers         */
  115. PRIVATE char *secret_key    = NULL;    /* Browser's latest secret key       */
  116. PRIVATE HTAASetup *current_setup= NULL;    /* The server setup we are currently */
  117.                                         /* talking to                 */
  118. PRIVATE char *current_hostname    = NULL;    /* The server's name and portnumber  */
  119. PRIVATE int current_portnumber    = 80;    /* where we are currently trying to  */
  120.                                         /* connect.                 */
  121. PRIVATE char *current_docname    = NULL;    /* The document's name we are        */
  122.                                         /* trying to access.             */
  123. PRIVATE char *HTAAForwardAuth    = NULL;    /* Authorization: line to forward    */
  124.                                         /* (used by gateway httpds)         */
  125.  
  126.  
  127. /*** HTAAForwardAuth for enabling gateway-httpds to forward Authorization ***/
  128.  
  129. PUBLIC void HTAAForwardAuth_set ARGS2(CONST char *, scheme_name,
  130.                       CONST char *, scheme_specifics)
  131. {
  132.     int len = 20 + (scheme_name      ? strlen(scheme_name)      : 0) 
  133.              + (scheme_specifics ? strlen(scheme_specifics) : 0);
  134.  
  135.     FREE(HTAAForwardAuth);
  136.     if (!(HTAAForwardAuth = (char*)malloc(len)))
  137.     outofmem(__FILE__, "HTAAForwardAuth_set");
  138.  
  139.     strcpy(HTAAForwardAuth, "Authorization: ");
  140.     if (scheme_name) {
  141.     strcat(HTAAForwardAuth, scheme_name);
  142.     strcat(HTAAForwardAuth, " ");
  143.     if (scheme_specifics) {
  144.         strcat(HTAAForwardAuth, scheme_specifics);
  145.     }
  146.     }
  147. }
  148.  
  149.  
  150. PUBLIC void HTAAForwardAuth_reset NOARGS
  151. {
  152.     FREE(HTAAForwardAuth);
  153. }
  154.  
  155.  
  156. /**************************** HTAAServer ***********************************/
  157.  
  158.  
  159. /* PRIVATE                        HTAAServer_new()
  160. **        ALLOCATE A NEW NODE TO HOLD SERVER INFO
  161. **        AND ADD IT TO THE LIST OF SERVERS
  162. ** ON ENTRY:
  163. **    hostname    is the name of the host that the server
  164. **            is running in.
  165. **    portnumber    is the portnumber which the server listens.
  166. **
  167. ** ON EXIT:
  168. **    returns        the newly-allocated node with all the strings
  169. **            duplicated.
  170. **            Strings will be automatically freed by
  171. **            the function HTAAServer_delete(), which also
  172. **            frees the node itself.
  173. */
  174. PRIVATE HTAAServer *HTAAServer_new ARGS2(CONST char*,    hostname,
  175.                      int,        portnumber)
  176. {
  177.     HTAAServer *server;
  178.  
  179.     if (!(server = (HTAAServer *)malloc(sizeof(HTAAServer))))
  180.     outofmem(__FILE__, "HTAAServer_new");
  181.  
  182.     server->hostname    = NULL;
  183.     server->portnumber    = (portnumber > 0 ? portnumber : 80);
  184.     server->setups    = HTList_new();
  185.     server->realms    = HTList_new();
  186.  
  187.     if (hostname) StrAllocCopy(server->hostname, hostname);
  188.  
  189.     if (!server_table) server_table = HTList_new();
  190.     
  191.     HTList_addObject(server_table, (void*)server);
  192.  
  193.     return server;
  194. }
  195.  
  196.  
  197. /* PRIVATE                        HTAAServer_delete()
  198. **
  199. **    DELETE THE ENTRY FOR THE SERVER FROM THE HOST TABLE,
  200. **    AND FREE THE MEMORY USED BY IT.
  201. **
  202. ** ON ENTRY:
  203. **    killme        points to the HTAAServer to be freed.
  204. **
  205. ** ON EXIT:
  206. **    returns        nothing.
  207. */
  208. #ifdef NOT_NEEDED_IT_SEEMS
  209. PRIVATE void HTAASetup_delete();    /* Forward */
  210. PRIVATE void HTAAServer_delete ARGS1(HTAAServer *, killme)
  211. {
  212.     if (killme) {
  213.     HTList *cur1 = killme->setups;
  214.     HTList *cur2 = killme->realms;
  215.     HTAASetup *setup;
  216.     HTAARealm *realm;
  217.  
  218.     while (NULL != (setup = (HTAASetup*)HTList_nextObject(cur1)))
  219.         HTAASetup_delete(setup);
  220.     HTList_delete(killme->setups);
  221.  
  222.     while (NULL != (realm = (HTAARealm*)HTList_nextObject(cur2)))
  223.         ;    /* This sould free() the realm */
  224.     HTList_delete(killme->realms);
  225.  
  226.     FREE(killme->hostname);
  227.  
  228.     HTList_removeObject(server_table, (void*)killme);
  229.  
  230.     free(killme);
  231.     }
  232. }
  233. #endif /*NOT_NEEDED_IT_SEEMS*/
  234.  
  235.  
  236. /* PRIVATE                        HTAAServer_lookup()
  237. **        LOOK UP SERVER BY HOSTNAME AND PORTNUMBER
  238. ** ON ENTRY:
  239. **    hostname    obvious.
  240. **    portnumber    if non-positive defaults to 80.
  241. **
  242. **    Looks up the server in the module-global server_table.
  243. **
  244. ** ON EXIT:
  245. **    returns        pointer to a HTAAServer structure
  246. **            representing the looked-up server.
  247. **            NULL, if not found.
  248. */
  249. PRIVATE HTAAServer *HTAAServer_lookup ARGS2(CONST char *, hostname,
  250.                         int,      portnumber)
  251. {
  252.     if (hostname) {
  253.     HTList *cur = server_table;
  254.     HTAAServer *server;
  255.  
  256.     if (portnumber <= 0) portnumber = 80;
  257.  
  258.     while (NULL != (server = (HTAAServer*)HTList_nextObject(cur))) {
  259.         if (server->portnumber == portnumber  &&
  260.         0==strcmp(server->hostname, hostname))
  261.         return server;
  262.     }
  263.     }
  264.     return NULL;    /* NULL parameter, or not found */
  265. }
  266.  
  267.  
  268.  
  269.  
  270. /*************************** HTAASetup *******************************/    
  271.  
  272.  
  273. /* PRIVATE                        HTAASetup_lookup()
  274. **    FIGURE OUT WHICH AUTHENTICATION SETUP THE SERVER
  275. **    IS USING FOR A GIVEN FILE ON A GIVEN HOST AND PORT
  276. **
  277. ** ON ENTRY:
  278. **    hostname    is the name of the server host machine.
  279. **    portnumber    is the port that the server is running in.
  280. **    docname        is the (URL-)pathname of the document we
  281. **            are trying to access.
  282. **
  283. **     This function goes through the information known about
  284. **    all the setups of the server, and finds out if the given
  285. **    filename resides in one of the protected directories.
  286. **
  287. ** ON EXIT:
  288. **    returns        NULL if no match.
  289. **            Otherwise, a HTAASetup structure representing
  290. **            the protected server setup on the corresponding
  291. **            document tree.
  292. **            
  293. */
  294. PRIVATE HTAASetup *HTAASetup_lookup ARGS3(CONST char *, hostname,
  295.                       int,        portnumber,
  296.                       CONST char *, docname)
  297. {
  298.     HTAAServer *server;
  299.     HTAASetup *setup;
  300.  
  301.     if (portnumber <= 0) portnumber = 80;
  302.  
  303.     if (hostname && docname && *hostname && *docname &&
  304.     NULL != (server = HTAAServer_lookup(hostname, portnumber))) {
  305.  
  306.     HTList *cur = server->setups;
  307. #ifndef RELEASE
  308.     if (TRACE) fprintf(stderr, "%s (%s:%d:%s)\n",
  309.                "HTAASetup_lookup: resolving setup for",
  310.                hostname, portnumber, docname);
  311. #endif /* RELEASE */
  312.  
  313.     while (NULL != (setup = (HTAASetup*)HTList_nextObject(cur))) {
  314.         if (HTAA_templateMatch(setup->template, docname)) {
  315. #ifndef RELEASE
  316.         if (TRACE) fprintf(stderr, "%s `%s' %s `%s'\n",
  317.                    "HTAASetup_lookup:", docname,
  318.                    "matched template", setup->template);
  319. #endif /* RELEASE */
  320.         return setup;
  321.         }
  322. #ifndef RELEASE
  323.         else if (TRACE) fprintf(stderr, "%s `%s' %s `%s'\n",
  324.                     "HTAASetup_lookup:", docname,
  325.                     "did NOT match template", setup->template);
  326. #endif /* RELEASE */
  327.     } /* while setups remain */
  328.     } /* if valid parameters and server found */
  329.  
  330. #ifndef RELEASE
  331.     if (TRACE) fprintf(stderr, "%s `%s' %s\n",
  332.                "HTAASetup_lookup: No template matched",
  333.                (docname ? docname : "(null)"),
  334.                "(so probably not protected)");
  335. #endif /* RELEASE */
  336.     return NULL;    /* NULL in parameters, or not found */
  337. }
  338.  
  339.  
  340.  
  341.  
  342. /* PRIVATE                        HTAASetup_new()
  343. **            CREATE A NEW SETUP NODE
  344. ** ON ENTRY:
  345. **    server        is a pointer to a HTAAServer structure
  346. **            to which this setup belongs.
  347. **    template    documents matching this template
  348. **            are protected according to this setup.
  349. **    valid_schemes    a list containing all valid authentication
  350. **            schemes for this setup.
  351. **            If NULL, all schemes are disallowed.
  352. **    scheme_specifics is an array of assoc lists, which
  353. **            contain scheme specific parameters given
  354. **            by server in Authenticate: fields.
  355. **            If NULL, all scheme specifics are
  356. **            set to NULL.
  357. ** ON EXIT:
  358. **    returns        a new HTAASetup node, and also adds it as
  359. **            part of the HTAAServer given as parameter.
  360. */
  361. PRIVATE HTAASetup *HTAASetup_new ARGS4(HTAAServer *,    server,
  362.                        char *,        template,
  363.                        HTList *,    valid_schemes,
  364.                        HTAssocList **,    scheme_specifics)
  365. {
  366.     HTAASetup *setup;
  367.  
  368.     if (!server || !template || !*template) return NULL;
  369.  
  370.     if (!(setup = (HTAASetup*)malloc(sizeof(HTAASetup))))
  371.     outofmem(__FILE__, "HTAASetup_new");
  372.  
  373.     setup->retry = NO;
  374.     setup->server = server;
  375.     setup->template = NULL;
  376.     if (template) StrAllocCopy(setup->template, template);
  377.     setup->valid_schemes = valid_schemes;
  378.     setup->scheme_specifics = scheme_specifics;
  379.  
  380.     HTList_addObject(server->setups, (void*)setup);
  381.  
  382.     return setup;
  383. }
  384.  
  385.  
  386.  
  387. /* PRIVATE                        HTAASetup_delete()
  388. **            FREE A HTAASetup STRUCTURE
  389. ** ON ENTRY:
  390. **    killme        is a pointer to the structure to free().
  391. **
  392. ** ON EXIT:
  393. **    returns        nothing.
  394. */
  395. #ifdef NOT_NEEDED_IT_SEEMS
  396. PRIVATE void HTAASetup_delete ARGS1(HTAASetup *, killme)
  397. {
  398.     int scheme;
  399.  
  400.     if (killme) {
  401.     if (killme->template) free(killme->template);
  402.     if (killme->valid_schemes)
  403.         HTList_delete(killme->valid_schemes);
  404.     for (scheme=0; scheme < HTAA_MAX_SCHEMES; scheme++)
  405.         if (killme->scheme_specifics[scheme])
  406.         HTAssocList_delete(killme->scheme_specifics[scheme]);
  407.     free(killme);
  408.     }
  409. }
  410. #endif /*NOT_NEEDED_IT_SEEMS*/
  411.  
  412.  
  413.  
  414. /* PRIVATE                    HTAASetup_updateSpecifics()
  415. *        COPY SCHEME SPECIFIC PARAMETERS
  416. **        TO HTAASetup STRUCTURE
  417. ** ON ENTRY:
  418. **    setup        destination setup structure.
  419. **    specifics    string array containing scheme
  420. **            specific parameters for each scheme.
  421. **            If NULL, all the scheme specific
  422. **            parameters are set to NULL.
  423. **
  424. ** ON EXIT:
  425. **    returns        nothing.
  426. */
  427. PRIVATE void HTAASetup_updateSpecifics ARGS2(HTAASetup *,    setup,
  428.                          HTAssocList **,    specifics)
  429. {
  430.     int scheme;
  431.  
  432.     if (setup) {
  433.     if (setup->scheme_specifics) {
  434.         for (scheme=0; scheme < HTAA_MAX_SCHEMES; scheme++) {
  435.         if (setup->scheme_specifics[scheme])
  436.             HTAssocList_delete(setup->scheme_specifics[scheme]);
  437.         }
  438.         free(setup->scheme_specifics);
  439.     }
  440.     setup->scheme_specifics = specifics;
  441.     }
  442. }
  443.  
  444.  
  445.  
  446.  
  447. /*************************** HTAARealm **********************************/
  448.  
  449. /* PRIVATE                         HTAARealm_lookup()
  450. **        LOOKUP HTAARealm STRUCTURE BY REALM NAME
  451. ** ON ENTRY:
  452. **    realm_table    a list of realm objects.
  453. **    realmname    is the name of realm to look for.
  454. **
  455. ** ON EXIT:
  456. **    returns        the realm.  NULL, if not found.
  457. */
  458. PRIVATE HTAARealm *HTAARealm_lookup ARGS2(HTList *,    realm_table,
  459.                       CONST char *, realmname)
  460. {
  461.     if (realm_table && realmname) {
  462.     HTList *cur = realm_table;
  463.     HTAARealm *realm;
  464.     
  465.     while (NULL != (realm = (HTAARealm*)HTList_nextObject(cur))) {
  466.         if (0==strcmp(realm->realmname, realmname))
  467.         return realm;
  468.     }
  469.     }
  470.     return NULL;    /* No table, NULL param, or not found */
  471. }
  472.  
  473.  
  474.  
  475. /* PRIVATE                        HTAARealm_new()
  476. **        CREATE A NODE CONTAINING USERNAME AND
  477. **        PASSWORD USED FOR THE GIVEN REALM.
  478. **        IF REALM ALREADY EXISTS, CHANGE
  479. **        USERNAME/PASSWORD.
  480. ** ON ENTRY:
  481. **    realm_table    a list of realms to where to add
  482. **            the new one, too.
  483. **    realmname    is the name of the password domain.
  484. **    username    and
  485. **    password    are what you can expect them to be.
  486. **
  487. ** ON EXIT:
  488. **    returns        the created realm.
  489. */
  490. PRIVATE HTAARealm *HTAARealm_new ARGS4(HTList *,    realm_table,
  491.                        CONST char *,    realmname,
  492.                        CONST char *,    username,
  493.                        CONST char *,    password)
  494. {
  495.     HTAARealm *realm;
  496.  
  497.     realm = HTAARealm_lookup(realm_table, realmname);
  498.  
  499.     if (!realm) {
  500.     if (!(realm = (HTAARealm*)malloc(sizeof(HTAARealm))))
  501.         outofmem(__FILE__, "HTAARealm_new");
  502.     realm->realmname = NULL;
  503.     realm->username = NULL;
  504.     realm->password = NULL;
  505.     StrAllocCopy(realm->realmname, realmname);
  506.     if (realm_table) HTList_addObject(realm_table, (void*)realm);
  507.     }
  508.     if (username) StrAllocCopy(realm->username, username);
  509.     if (password) StrAllocCopy(realm->password, password);
  510.  
  511.     return realm;
  512. }
  513.  
  514.  
  515.  
  516.  
  517. /***************** Basic and Pubkey Authentication ************************/
  518.  
  519. /* PRIVATE                        compose_auth_string()
  520. **
  521. **        COMPOSE Basic OR Pubkey AUTHENTICATION STRING;
  522. **        PROMPTS FOR USERNAME AND PASSWORD IF NEEDED
  523. **
  524. ** ON ENTRY:
  525. **    scheme        is either HTAA_BASIC or HTAA_PUBKEY.
  526. **    realmname    is the password domain name.
  527. **
  528. ** ON EXIT:
  529. **    returns        a newly composed authorization string,
  530. **            (with, of course, a newly generated secret
  531. **            key and fresh timestamp, if Pubkey-scheme
  532. **            is being used).
  533. **            NULL, if something fails.
  534. ** NOTE:
  535. **    Like throughout the entire AA package, no string or structure
  536. **    returned by AA package needs to (or should) be freed.
  537. **
  538. */
  539. PRIVATE char *compose_auth_string ARGS2(HTAAScheme,    scheme,
  540.                     HTAASetup *,    setup)
  541. {
  542.     static char *result = NULL;    /* Uuencoded presentation, the result */
  543.     char *cleartext = NULL;    /* Cleartext presentation */
  544.     char *ciphertext = NULL;    /* Encrypted presentation */
  545.     int len;
  546.     char *username;
  547.     char *password;
  548.     char *realmname;
  549.     HTAARealm *realm;
  550.     char *inet_addr = "0.0.0.0";    /* Change... @@@@ */
  551.     char *timestamp = "42";        /* ... these @@@@ */
  552.     
  553.  
  554.     FREE(result);    /* From previous call */
  555.  
  556.     if ((scheme != HTAA_BASIC && scheme != HTAA_PUBKEY) || !setup ||
  557.     !setup->scheme_specifics || !setup->scheme_specifics[scheme] ||
  558.     !setup->server  ||  !setup->server->realms)
  559.     return NULL;
  560.  
  561.     realmname = HTAssocList_lookup(setup->scheme_specifics[scheme], "realm");
  562.     if (!realmname) return NULL;
  563.  
  564.     realm = HTAARealm_lookup(setup->server->realms, realmname);
  565.     if (!realm || setup->retry) {
  566.     char msg[100];
  567.  
  568.     if (!realm) {
  569. #ifndef RELEASE
  570.         if (TRACE) fprintf(stderr, "%s `%s' %s\n",
  571.                    "compose_auth_string: realm:", realmname,
  572.                    "not found -- creating");
  573. #endif /* RELEASE */
  574.         realm = HTAARealm_new(setup->server->realms, realmname, NULL,NULL);
  575.         sprintf(msg,
  576.             "Document is protected. Enter username for %s at %s",
  577.             realm->realmname,
  578.             setup->server->hostname ? setup->server->hostname : "??");
  579.     }
  580.     else {
  581.         sprintf(msg,"Enter username for %s at %s", realm->realmname,
  582.             setup->server->hostname ? setup->server->hostname : "??");
  583.     }
  584.  
  585.     username = realm->username;
  586.     password = NULL;
  587.     HTPromptUsernameAndPassword(msg, &username, &password);
  588.  
  589.     FREE(realm->username);
  590.     FREE(realm->password);
  591.     realm->username = username;
  592.     realm->password = password;
  593.  
  594.     if (!realm->username)
  595.         return NULL;        /* Suggested by marca; thanks! */
  596.     }
  597.     
  598.     len = strlen(realm->username ? realm->username : "") +
  599.       strlen(realm->password ? realm->password : "") + 3;
  600.  
  601.     if (scheme == HTAA_PUBKEY) {
  602. #ifdef PUBKEY
  603.     /* Generate new secret key */
  604.     StrAllocCopy(secret_key, HTAA_generateRandomKey());
  605. #endif
  606.     /* Room for secret key, timestamp and inet address */
  607.     len += strlen(secret_key ? secret_key : "") + 30;
  608.     }
  609.     else
  610.     FREE(secret_key);
  611.  
  612.     if (!(cleartext  = (char*)calloc(len, 1)))
  613.     outofmem(__FILE__, "compose_auth_string");
  614.  
  615.     if (realm->username) strcpy(cleartext, realm->username);
  616.     else *cleartext = (char)0;
  617.  
  618.     strcat(cleartext, ":");
  619.  
  620.     if (realm->password) strcat(cleartext, realm->password);
  621.  
  622.     if (scheme == HTAA_PUBKEY) {
  623.     strcat(cleartext, ":");
  624.     strcat(cleartext, inet_addr);
  625.     strcat(cleartext, ":");
  626.     strcat(cleartext, timestamp);
  627.     strcat(cleartext, ":");
  628.     if (secret_key) strcat(cleartext, secret_key);
  629.  
  630.     if (!((ciphertext = (char*)malloc(2*len)) &&
  631.           (result     = (char*)malloc(3*len))))
  632.         outofmem(__FILE__, "compose_auth_string");
  633. #ifdef PUBKEY
  634.     HTPK_encrypt(cleartext, ciphertext, server->public_key);
  635.     HTUU_encode((unsigned char *)ciphertext, strlen(ciphertext), result);
  636. #endif
  637.     free(cleartext);
  638.     free(ciphertext);
  639.     }
  640.     else { /* scheme == HTAA_BASIC */
  641.     if (!(result = (char*)malloc(4 * ((len+2)/3) + 1)))
  642.         outofmem(__FILE__, "compose_auth_string");
  643.     HTUU_encode((unsigned char *)cleartext, strlen(cleartext), result);
  644.     free(cleartext);
  645.     }
  646.     return result;
  647. }
  648.  
  649.  
  650.  
  651. /* BROWSER PRIVATE                    HTAA_selectScheme()
  652. **        SELECT THE AUTHENTICATION SCHEME TO USE
  653. ** ON ENTRY:
  654. **    setup    is the server setup structure which can
  655. **        be used to make the decision about the
  656. **        used scheme.
  657. **
  658. **    When new authentication methods are added to library
  659. **    this function makes the decision about which one to
  660. **    use at a given time.  This can be done by inspecting
  661. **    environment variables etc.
  662. **
  663. **    Currently only searches for the first valid scheme,
  664. **    and if nothing found suggests Basic scheme;
  665. **
  666. ** ON EXIT:
  667. **    returns    the authentication scheme to use.
  668. */
  669. PRIVATE HTAAScheme HTAA_selectScheme ARGS1(HTAASetup *, setup)
  670. {
  671.     HTAAScheme scheme;
  672.  
  673.     if (setup && setup->valid_schemes) {
  674.     for (scheme=HTAA_BASIC; scheme < HTAA_MAX_SCHEMES; scheme++)
  675.         if (-1 < HTList_indexOf(setup->valid_schemes, (void*)scheme))
  676.         return scheme;
  677.     }
  678.     return HTAA_BASIC;
  679. }
  680.  
  681.  
  682.  
  683.  
  684. /* BROWSER PUBLIC                    HTAA_composeAuth()
  685. **
  686. **    SELECT THE AUTHENTICATION SCHEME AND
  687. **    COMPOSE THE ENTIRE AUTHORIZATION HEADER LINE
  688. **    IF WE ALREADY KNOW THAT THE HOST REQUIRES AUTHENTICATION
  689. **
  690. ** ON ENTRY:
  691. **    hostname    is the hostname of the server.
  692. **    portnumber    is the portnumber in which the server runs.
  693. **    docname        is the pathname of the document (as in URL)
  694. **
  695. ** ON EXIT:
  696. **    returns    NULL, if no authorization seems to be needed, or
  697. **        if it is the entire Authorization: line, e.g.
  698. **
  699. **           "Authorization: Basic username:password"
  700. **
  701. **        As usual, this string is automatically freed.
  702. */
  703. PUBLIC char *HTAA_composeAuth ARGS3(CONST char *,    hostname,
  704.                     CONST int,        portnumber,
  705.                     CONST char *,    docname)
  706. {
  707.     static char *result = NULL;
  708.     char *auth_string;
  709.     BOOL retry;
  710.     HTAAScheme scheme;
  711.  
  712.     /*
  713.     ** Make gateway httpds pass authorization field as it was received.
  714.     ** (This still doesn't really work because Authenticate: headers
  715.     **  from remote server are not forwarded to client yet so it cannot
  716.     **  really know that it should send authorization;  I will not
  717.     **  implement it yet because I feel we will soon change radically
  718.     **  the way requests are represented to allow multithreading
  719.     **  on server-side.  Life is hard.)
  720.     */
  721.     if (HTAAForwardAuth) {
  722. #ifndef RELEASE
  723.     if (TRACE) fprintf(stderr, "HTAA_composeAuth: %s\n",
  724.                "Forwarding received authorization");
  725. #endif /* RELEASE */
  726.     StrAllocCopy(result, HTAAForwardAuth);
  727.     HTAAForwardAuth_reset();    /* Just a precaution */
  728.     return result;
  729.     }
  730.  
  731.     FREE(result);            /* From previous call */
  732.  
  733. #ifndef RELEASE
  734.     if (TRACE)
  735.     fprintf(stderr,
  736.         "Composing Authorization for %s:%d/%s\n",
  737.         hostname, portnumber, docname);
  738. #endif /* RELEASE */
  739.  
  740.     if (current_portnumber != portnumber ||
  741.     !current_hostname || !current_docname ||
  742.     !hostname         || !docname         ||
  743.     0 != strcmp(current_hostname, hostname) ||
  744.     0 != strcmp(current_docname, docname)) {
  745.  
  746.     retry = NO;
  747.  
  748.     current_portnumber = portnumber;
  749.     
  750.     if (hostname) StrAllocCopy(current_hostname, hostname);
  751.     else FREE(current_hostname);
  752.  
  753.     if (docname) StrAllocCopy(current_docname, docname);
  754.     else FREE(current_docname);
  755.     }
  756.     else retry = YES;
  757.     
  758.     if (!current_setup || !retry)
  759.     current_setup = HTAASetup_lookup(hostname, portnumber, docname);
  760.  
  761.     if (!current_setup)
  762.     return NULL;
  763.  
  764.  
  765.     switch (scheme = HTAA_selectScheme(current_setup)) {
  766.       case HTAA_BASIC:
  767.       case HTAA_PUBKEY:
  768.     auth_string = compose_auth_string(scheme, current_setup);
  769.     break;
  770.       case HTAA_KERBEROS_V4:
  771.     /* OTHER AUTHENTICATION ROUTINES ARE CALLED HERE */
  772.       default:
  773.     {
  774.         char msg[100];
  775.         sprintf(msg, "%s %s `%s'",
  776.             "This client doesn't know how to compose authentication",
  777.             "information for scheme", HTAAScheme_name(scheme));
  778.         HTAlert(msg);
  779.         auth_string = NULL;
  780.     }
  781.     } /* switch scheme */
  782.  
  783.     current_setup->retry = NO;
  784.  
  785.     /* Added by marca. */
  786.     if (!auth_string)
  787.     return NULL;
  788.     
  789.     if (!(result = (char*)malloc(sizeof(char) * (strlen(auth_string)+40))))
  790.     outofmem(__FILE__, "HTAA_composeAuth");
  791.     strcpy(result, "Authorization: ");
  792.     strcat(result, HTAAScheme_name(scheme));
  793.     strcat(result, " ");
  794.     strcat(result, auth_string);
  795.     return result;
  796. }
  797.  
  798.  
  799.  
  800.  
  801. /* BROWSER PUBLIC                HTAA_shouldRetryWithAuth()
  802. **
  803. **        DETERMINES IF WE SHOULD RETRY THE SERVER
  804. **        WITH AUTHORIZATION
  805. **        (OR IF ALREADY RETRIED, WITH A DIFFERENT
  806. **        USERNAME AND/OR PASSWORD (IF MISSPELLED))
  807. ** ON ENTRY:
  808. **    start_of_headers is the first block already read from socket,
  809. **            but status line skipped; i.e. points to the
  810. **            start of the header section.
  811. **    length        is the remaining length of the first block.
  812. **    soc        is the socket to read the rest of server reply.
  813. **
  814. **            This function should only be called when
  815. **            server has replied with a 401 (Unauthorized)
  816. **            status code.
  817. ** ON EXIT:
  818. **    returns        YES, if connection should be retried.
  819. **                 The node containing all the necessary
  820. **                 information is
  821. **                * either constructed if it does not exist
  822. **                * or password is reset to NULL to indicate
  823. **                  that username and password should be
  824. **                  reprompted when composing Authorization:
  825. **                  field (in function HTAA_composeAuth()).
  826. **            NO, otherwise.
  827. */
  828. PUBLIC BOOL HTAA_shouldRetryWithAuth ARGS3(char *, start_of_headers,
  829.                        int,       length,
  830.                        int,       soc)
  831. {
  832.     HTAAScheme scheme;
  833.     char *line;
  834.     int num_schemes = 0;
  835.     HTList *valid_schemes = HTList_new();
  836.     HTAssocList **scheme_specifics = NULL;
  837.     char *template = NULL;
  838.  
  839.  
  840.     /* Read server reply header lines */
  841.  
  842. #ifndef RELEASE
  843.     if (TRACE)
  844.     fprintf(stderr, "Server reply header lines:\n");
  845. #endif /* RELEASE */
  846.  
  847.     HTAA_setupReader(start_of_headers, length, soc);
  848.     while (NULL != (line = HTAA_getUnfoldedLine())  &&  *line != (char)0) {
  849.  
  850. #ifndef RELEASE
  851.     if (TRACE) fprintf(stderr, "%s\n", line);
  852. #endif /* RELEASE */
  853.  
  854.     if (strchr(line, ':')) {    /* Valid header line */
  855.  
  856.         char *p = line;
  857.         char *fieldname = HTNextField(&p);
  858.         char *arg1 = HTNextField(&p);
  859.         char *args = p;
  860.         
  861.         if (0==strcasecomp(fieldname, "WWW-Authenticate:")) {
  862.         if (HTAA_UNKNOWN != (scheme = HTAAScheme_enum(arg1))) {
  863.             HTList_addObject(valid_schemes, (void*)scheme);
  864.             if (!scheme_specifics) {
  865.             int i;
  866.             scheme_specifics = (HTAssocList**)
  867.                 malloc(HTAA_MAX_SCHEMES * sizeof(HTAssocList*));
  868.             if (!scheme_specifics)
  869.                 outofmem(__FILE__, "HTAA_shouldRetryWithAuth");
  870.             for (i=0; i < HTAA_MAX_SCHEMES; i++)
  871.                 scheme_specifics[i] = NULL;
  872.             }
  873.             scheme_specifics[scheme] = HTAA_parseArgList(args);
  874.             num_schemes++;
  875.         }
  876. #ifndef RELEASE
  877.         else if (TRACE) {
  878.             fprintf(stderr, "Unknown scheme `%s' %s\n",
  879.                 (arg1 ? arg1 : "(null)"),
  880.                 "in WWW-Authenticate: field");
  881.         }
  882. #endif /* RELEASE */
  883.         }
  884.  
  885.         else if (0==strcasecomp(fieldname, "WWW-Protection-Template:")) {
  886. #ifndef RELEASE
  887.         if (TRACE)
  888.             fprintf(stderr, "Protection template set to `%s'\n", arg1);
  889. #endif /* RELEASE */
  890.         StrAllocCopy(template, arg1);
  891.         }
  892.  
  893.     } /* if a valid header line */
  894. #ifndef RELEASE
  895.     else if (TRACE) {
  896.         fprintf(stderr, "Invalid header line `%s' ignored\n", line);
  897.     } /* else invalid header line */
  898. #endif /* RELEASE */
  899.     } /* while header lines remain */
  900.  
  901.  
  902.     /* So should we retry with authorization */
  903.  
  904.     if (num_schemes == 0) {        /* No authentication valid */
  905.     current_setup = NULL;
  906.     return NO;
  907.     }
  908.  
  909.     if (current_setup && current_setup->server) {
  910.     /* So we have already tried with authorization.    */
  911.     /* Either we don't have access or username or    */
  912.     /* password was misspelled.            */
  913.         
  914.     /* Update scheme-specific parameters    */
  915.     /* (in case they have expired by chance).    */
  916.     HTAASetup_updateSpecifics(current_setup, scheme_specifics);
  917.  
  918.     if (NO == HTConfirm("Authorization failed.  Retry?")) {
  919.         current_setup = NULL;
  920.         return NO;
  921.     } /* HTConfirm(...) == NO */
  922.     else { /* re-ask username+password (if misspelled) */
  923.         current_setup->retry = YES;
  924.         return YES;
  925.     } /* HTConfirm(...) == YES */
  926.     } /* if current_setup != NULL */
  927.  
  928.     else { /* current_setup == NULL, i.e. we have a     */
  929.        /* first connection to a protected server or  */
  930.        /* the server serves a wider set of documents */
  931.        /* than we expected so far.                   */
  932.  
  933.     HTAAServer *server = HTAAServer_lookup(current_hostname,
  934.                            current_portnumber);
  935.     if (!server) {
  936.         server = HTAAServer_new(current_hostname,
  937.                     current_portnumber);
  938.     }
  939.     if (!template)
  940.         template = HTAA_makeProtectionTemplate(current_docname);
  941.     current_setup = HTAASetup_new(server, 
  942.                       template,
  943.                       valid_schemes,
  944.                       scheme_specifics);
  945.  
  946.         HTAlert("Access without authorization denied -- retrying");
  947.     return YES;
  948.     } /* else current_setup == NULL */
  949.  
  950.     /* Never reached */
  951. }
  952.  
  953.